#ifndef AVALON_PIPEDREADER_HPP
#define AVALON_PIPEDREADER_HPP
#include "Avalon/IO/Buffer.hpp"
#include "Avalon/IO/Reader.hpp"
#include "Avalon/Threading/Async.hpp"

namespace Avalon {
namespace IO {

  /*! \class PipedReader
   *  \brief Reads the contents written by a PipedWriter.
   */
  class PipedReader : public Reader {
    public:

      //! Constructs a PipedReader.
      PipedReader();

      virtual ~PipedReader();

      //! Breaks the pipe.
      void Break();

      //! Breaks the pipe with an exception.
      /*!
        \param cause The exception to raise on a read operation.
      */
      void Break(const boost::exception_ptr& cause);

      virtual void Read(void* destination, int size,
        Out<Threading::Async<int> > sizeRead);

      virtual void Read(Buffer* destination, int size,
        Out<Threading::Async<int> > sizeRead);

      using Reader::Read;

    private:
      friend class PipedWriter;
      boost::shared_ptr<boost::mutex> m_writeMutex;
      boost::mutex m_readMutex;
      Threading::Async<int>* m_result;
      Buffer* m_buffer;
      void* m_destination;
      int m_size;
      Buffer m_source;
      const char* m_readIterator;
      int m_readRemaining;
      PipedWriter* m_writer;
      boost::exception_ptr m_cause;

      void Connect(PipedWriter* writer);
      void InternalBreak(boost::unique_lock<boost::mutex>& readLock,
        boost::unique_lock<boost::mutex>& writeLock);
      void Write(const void* data, int size,
        boost::unique_lock<boost::mutex>& readLock,
        boost::unique_lock<boost::mutex>& writeLock);
  };
}
}

#endif // AVALON_PIPEDREADER_HPP
